/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef skgpu_VulkanMemory_DEFINED
#define skgpu_VulkanMemory_DEFINED

#include "include/gpu/GpuTypes.h"
#include "include/gpu/vk/VulkanMemoryAllocator.h"
#include "include/gpu/vk/VulkanTypes.h"
#include "include/private/base/SkTArray.h"

#include <functional>

namespace skgpu {
namespace VulkanMemory {
using CheckResult = bool(VkResult);

bool AllocBufferMemory(VulkanMemoryAllocator *, VkBuffer buffer, skgpu::VulkanMemoryAllocator::BufferUsage,
    bool shouldPersistentlyMapCpuToGpu, const std::function<CheckResult> &, VulkanAlloc *alloc);

void FreeBufferMemory(VulkanMemoryAllocator *, const VulkanAlloc &alloc);

bool AllocImageMemory(VulkanMemoryAllocator *, VkImage image, skgpu::Protected isProtected, bool forceDedicatedMemory,
    bool useLazyAllocation, const std::function<CheckResult> &, VulkanAlloc *alloc);

void FreeImageMemory(VulkanMemoryAllocator *, const VulkanAlloc &alloc);

// Maps the entire skgpu::VulkanAlloc and returns a pointer to the start of the allocation.
// Underneath the hood, we may map more than the range of the skgpu::VulkanAlloc (e.g. the
// entire VkDeviceMemory), but the pointer returned will always be to the start of the
// skgpu::VulkanAlloc. The caller should also never assume more than the skgpu::VulkanAlloc
// block has been mapped.
void *MapAlloc(VulkanMemoryAllocator *, const VulkanAlloc &, const std::function<CheckResult> &);
void UnmapAlloc(VulkanMemoryAllocator *, const VulkanAlloc &alloc);

// For the Flush and Invalidate calls, the offset should be relative to the skgpu::VulkanAlloc.
// Thus this will often be 0. The client does not need to make sure the offset and size are
// aligned to the nonCoherentAtomSize, the internal calls will handle that.
void FlushMappedAlloc(VulkanMemoryAllocator *, const skgpu::VulkanAlloc &, VkDeviceSize offset, VkDeviceSize size,
    const std::function<CheckResult> &);
void InvalidateMappedAlloc(VulkanMemoryAllocator *, const VulkanAlloc &alloc, VkDeviceSize offset, VkDeviceSize size,
    const std::function<CheckResult> &);

// Helper for aligning and setting VkMappedMemoryRange for flushing/invalidating noncoherent
// memory.
void GetNonCoherentMappedMemoryRange(const VulkanAlloc &, VkDeviceSize offset, VkDeviceSize size,
    VkDeviceSize alignment, VkMappedMemoryRange *);
} // namespace VulkanMemory
} // namespace skgpu

#endif
